home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / doom / suckmods.zip / SUCKMODS.ZIP / suck05 / src / weapons.qc < prev    next >
Text File  |  1997-05-13  |  54KB  |  2,314 lines

  1. void(entity e, float chan, string samp, float vol, float atten) playsound;
  2. void (entity targ, entity inflictor, entity attacker, float damage) T_Damage;
  3. void () player_run;
  4. void(entity bomb, entity attacker, float rad, entity ignore) T_RadiusDamage;
  5. void(vector org, vector vel, float color, float damage) SpawnBlood;
  6. void() SuperDamageSound;
  7. void() HasteSound;
  8. void() TossRune;
  9. void() bound_other_ammo;
  10. void() RuneTouch;
  11. void() RuneRespawn;
  12. void(vector org) spawn_tfog;
  13. void(vector org, entity death_owner) spawn_tdeath;
  14. void(entity bomb, entity attacker, float rad, entity ignore) T_DischargeDamage;
  15. void(vector org, vector dir) launch_spike;
  16. entity(float disp) identify_player;
  17. void() bubble_bob;
  18. void() InitRune;
  19. void () regimpulse;
  20. void () checkregimpulse;
  21. void () PrintHelp;
  22. void () RuneInfo;
  23. void () GroupPowerInfo;
  24. void () KiziTeleportToBase;
  25. void () ShogunTeleport;
  26.  
  27. // SUCK: Print everyone's kills and deaths to the console.
  28. void() PrintStats =
  29. {
  30.     local entity e, guy;
  31.     local float min, last_min;
  32.     local string s;
  33.     local float done;
  34.  
  35.     guy=find(world, classname, "player");
  36.     while (guy!=world)
  37.     {
  38.             sprint(self, guy.netname);
  39.             sprint(self, ": Kills: ");
  40.             s=ftos(guy.num_kills);
  41.             sprint(self, s);
  42.             sprint(self, " Deaths: ");
  43.             s=ftos(guy.num_deaths);
  44.             sprint(self, s);
  45.             sprint(self, "\n");
  46.         guy=find(guy, classname, "player"); 
  47.     }
  48.     return;
  49.     last_min=-9999;
  50.     done=0;
  51.     while (done!=1)
  52.     {
  53.         e=find(world, classname, "player");
  54.         min=e.num_kills;
  55.         guy=e;
  56.         while (e!=world)
  57.         {
  58.             if ((e.num_kills<=min) && (e.num_kills>=last_min))
  59.             {
  60.                 guy=e;
  61.                 min=e.num_kills;
  62.             }
  63.             e=find(world, classname, "player");
  64.         }
  65.         if (min==last_min)
  66.             done=1;
  67.         else
  68.         {
  69.             last_min=min;
  70.         }
  71.  
  72.     }
  73. };
  74.  
  75. // called by worldspawn
  76. void() W_Precache =
  77. {
  78.     precache_sound ("hknight/hit.wav");  // flamethrower
  79.  
  80.     precache_sound ("weapons/r_exp3.wav");    // new rocket explosion
  81.     precache_sound ("weapons/rocket1i.wav");    // spike gun
  82.     precache_sound ("weapons/sgun1.wav");
  83.     precache_sound ("weapons/guncock.wav");    // player shotgun
  84.     precache_sound ("weapons/ric1.wav");    // ricochet (used in c code)
  85.     precache_sound ("weapons/ric2.wav");    // ricochet (used in c code)
  86.     precache_sound ("weapons/ric3.wav");    // ricochet (used in c code)
  87.     precache_sound ("weapons/spike2.wav");    // super spikes
  88.     precache_sound ("weapons/tink1.wav");    // spikes tink (used in c code)
  89.     precache_sound ("weapons/grenade.wav");    // grenade launcher
  90.     precache_sound ("weapons/bounce.wav");        // grenade bounce
  91.     precache_sound ("weapons/shotgn2.wav");    // super shotgun
  92.  
  93.  
  94.  
  95.     precache_sound2 ("blob/land1.wav");     // chain go splorch!
  96.     if (cvar("teamplay") & TEAM_CAPTURE_CUSTOM) {
  97.         precache_sound ("weapons/chain1.wav");
  98.         precache_sound ("weapons/chain2.wav");
  99.         precache_sound ("weapons/chain3.wav");
  100.         precache_sound ("weapons/bounce2.wav");
  101.     }
  102.  
  103.     // ZOID:
  104.     // normally the weapon models are precached in the individual item
  105.     // creation routines.  But since we've added impulse 21 we can drop
  106.     // weapons at any time.  Must precache all weapon models.
  107.     precache_model ("progs/g_shot.mdl");
  108.     precache_model ("progs/g_nail.mdl");
  109.     precache_model ("progs/g_nail2.mdl");
  110.     precache_model ("progs/g_rock.mdl");
  111.     precache_model ("progs/g_rock2.mdl");
  112.     precache_model ("progs/g_light.mdl");
  113.     precache_model ("progs/dog.mdl");
  114.     precache_sound ("dog/ddeath.wav");
  115.     precache_sound ("dog/dsight.wav");
  116.  
  117. };
  118.  
  119. float() crandom =
  120. {
  121.     return 2*(random() - 0.5);
  122. };
  123.  
  124. /*
  125. ================
  126. W_FireAxe
  127. ================
  128. */
  129. void() W_FireAxe =
  130. {
  131.     local    vector    source;
  132.     local    vector    org;
  133.     local vector f;
  134.  
  135.     if (self.rune_num == ITEM_RUNE_KIZI)
  136.         KiziTeleportToBase();
  137.  
  138.     if (self.rune_num == ITEM_RUNE_SHOGUN)
  139.         ShogunTeleport();
  140.  
  141.     makevectors (self.v_angle);
  142.     source = self.origin + '0 0 16';
  143.     if (self.rune_num == ITEM_RUNE_SAMURAI)
  144.         traceline (source, source + v_forward*640, FALSE, self);
  145.     else
  146.         traceline (source, source + v_forward*64, FALSE, self);
  147.     if (trace_fraction == 1.0)
  148.         return;
  149.     
  150.     org = trace_endpos - v_forward*4;
  151.  
  152.     if (trace_ent.takedamage)
  153.     {
  154.         trace_ent.axhitme = 1;
  155.         if (self.rune_num == ITEM_RUNE_VAMPIRE)
  156.             T_Damage (trace_ent, self, self, 80);
  157.         else if (self.rune_num == ITEM_RUNE_SAMURAI)
  158.             T_Damage (trace_ent, self, self, 60);
  159.         else 
  160.             T_Damage(trace_ent, self, self, 20);    
  161.  
  162.         if ((self.rune_num == ITEM_RUNE_VAMPIRE) ||
  163.         (self.rune_num == ITEM_RUNE_IFRITE))
  164.         {
  165.             if (trace_ent.rune_num == ITEM_RUNE_MONK)
  166.                 SpawnBlood (org, '0 0 0', 1, 50);
  167.             else
  168.                 SpawnBlood (org, '0 0 0', 73, 50);
  169.             f_x=1000*random();
  170.             f_y=1000*random();
  171.             f_z=1000*random();
  172.             launch_spike(self.origin, f);
  173.             newmis.solid=SOLID_NOT;
  174.             newmis.nextthink=time+1.5;
  175.             if (self.rune_num == ITEM_RUNE_VAMPIRE)
  176.                 setmodel(newmis, "progs/w_spike.mdl");
  177.             else
  178.                 setmodel(newmis, "progs/k_spike.mdl");
  179.             setsize(newmis, VEC_ORIGIN, VEC_ORIGIN);
  180.             f_x=1000*random();
  181.             f_y=1000*random();
  182.             f_z=1000*random();
  183.             launch_spike(self.origin, f);
  184.             newmis.solid=SOLID_NOT;
  185.             newmis.nextthink=time+1.5;
  186.             if (self.rune_num == ITEM_RUNE_VAMPIRE)
  187.                 setmodel(newmis, "progs/w_spike.mdl");
  188.             else
  189.                 setmodel(newmis, "progs/k_spike.mdl");
  190.             setsize(newmis, VEC_ORIGIN, VEC_ORIGIN);
  191.             f_x=1000*random();
  192.             f_y=1000*random();
  193.             f_z=1000*random();
  194.             launch_spike(self.origin, f);
  195.             newmis.solid=SOLID_NOT;
  196.             newmis.nextthink=time+1.5;
  197.             if (self.rune_num == ITEM_RUNE_VAMPIRE)
  198.                 setmodel(newmis, "progs/w_spike.mdl");
  199.             else
  200.                 setmodel(newmis, "progs/k_spike.mdl");
  201.             setsize(newmis, VEC_ORIGIN, VEC_ORIGIN);
  202.         }
  203.  
  204.         if (trace_ent.rune_num == ITEM_RUNE_MONK)
  205.             SpawnBlood (org, '0 0 0', 1, 20);
  206.         else
  207.             SpawnBlood (org, '0 0 0', 73, 20);
  208.     }
  209.     else
  210.     {    // hit wall
  211.         playsound (self, CHAN_WEAPON, "player/axhit2.wav", 1, ATTN_NORM);
  212.         WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  213.         WriteByte (MSG_BROADCAST, TE_GUNSHOT);
  214.         WriteCoord (MSG_BROADCAST, org_x);
  215.         WriteCoord (MSG_BROADCAST, org_y);
  216.         WriteCoord (MSG_BROADCAST, org_z);
  217.     }
  218. };
  219.  
  220.  
  221. //============================================================================
  222.  
  223.  
  224. vector() wall_velocity =
  225. {
  226.     local vector    vel;
  227.     
  228.     vel = normalize (self.velocity);
  229.     vel = normalize(vel + v_up*(random()- 0.5) + v_right*(random()- 0.5));
  230.     vel = vel + 2*trace_plane_normal;
  231.     vel = vel * 200;
  232.     
  233.     return vel;
  234. };
  235.  
  236.  
  237. /*
  238. ================
  239. SpawnMeatSpray
  240. ================
  241. */
  242. void(vector org, vector vel) SpawnMeatSpray =
  243. {
  244.     local    entity missile, mpuff;
  245.     local    vector    org;
  246.  
  247.     missile = spawn ();
  248.     missile.owner = self;
  249.     missile.movetype = MOVETYPE_BOUNCE;
  250.     missile.solid = SOLID_NOT;
  251.  
  252.     makevectors (self.angles);
  253.  
  254.     missile.velocity = vel;
  255.     missile.velocity_z = missile.velocity_z + 250 + 50*random();
  256.  
  257.     missile.avelocity = '3000 1000 2000';
  258.     
  259. // set missile duration
  260.     missile.nextthink = time + 1;
  261.     missile.think = SUB_Remove;
  262.  
  263.     setmodel (missile, "progs/zom_gib.mdl");
  264.     setsize (missile, '0 0 0', '0 0 0');        
  265.     setorigin (missile, org);
  266. };
  267.  
  268. /*
  269. ================
  270. SpawnBlood
  271. ================
  272. */
  273. void(vector org, vector vel, float color, float damage) SpawnBlood =
  274. {
  275.     particle (org, vel*0.1, color, damage*2);
  276. };
  277.  
  278. /*
  279. ================
  280. spawn_touchblood
  281. ================
  282. */
  283. void(float damage) spawn_touchblood =
  284. {
  285.     local vector    vel;
  286.  
  287.     vel = wall_velocity () * 0.2;
  288.     SpawnBlood (self.origin + vel*0.01, vel, 73, damage);
  289. };
  290.  
  291.  
  292. /*
  293. ================
  294. SpawnChunk
  295. ================
  296. */
  297. void(vector org, vector vel) SpawnChunk =
  298. {
  299.     particle (org, vel*0.02, 0, 10);
  300. };
  301.  
  302. /*
  303. ==============================================================================
  304.  
  305. MULTI-DAMAGE
  306.  
  307. Collects multiple small damages into a single damage
  308.  
  309. ==============================================================================
  310. */
  311.  
  312. entity    multi_ent;
  313. float    multi_damage;
  314.  
  315. void() ClearMultiDamage =
  316. {
  317.     multi_ent = world;
  318.     multi_damage = 0;
  319. };
  320.  
  321. void() ApplyMultiDamage =
  322. {
  323.     if (!multi_ent)
  324.         return;
  325.     T_Damage (multi_ent, self, self, multi_damage);
  326. };
  327.  
  328. void(entity hit, float damage) AddMultiDamage =
  329. {
  330.     if (!hit)
  331.         return;
  332.     
  333.     if (hit != multi_ent)
  334.     {
  335.         ApplyMultiDamage ();
  336.         multi_damage = damage;
  337.         multi_ent = hit;
  338.     }
  339.     else
  340.         multi_damage = multi_damage + damage;
  341. };
  342.  
  343. /*
  344. ==============================================================================
  345.  
  346. BULLETS
  347.  
  348. ==============================================================================
  349. */
  350.  
  351. /*
  352. ================
  353. TraceAttack
  354. ================
  355. */
  356. void(float damage, vector dir) TraceAttack =
  357. {
  358.     local    vector    vel, org;
  359.     
  360.     vel = normalize(dir + v_up*crandom() + v_right*crandom());
  361.     vel = vel + 2*trace_plane_normal;
  362.     vel = vel * 200;
  363.  
  364.     org = trace_endpos - dir*4;
  365.  
  366.     if (trace_ent.takedamage)
  367.     {
  368.         if (trace_ent.rune_num == ITEM_RUNE_MONK)
  369.             SpawnBlood (org, vel*0.2, 1, damage);
  370.         else
  371.             SpawnBlood (org, vel*0.2, 73, damage);
  372.         AddMultiDamage (trace_ent, damage);
  373.     }
  374.     else
  375.     {
  376.         WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  377.         WriteByte (MSG_BROADCAST, TE_GUNSHOT);
  378.         WriteCoord (MSG_BROADCAST, org_x);
  379.         WriteCoord (MSG_BROADCAST, org_y);
  380.         WriteCoord (MSG_BROADCAST, org_z);
  381.     }
  382. };
  383.  
  384. /*
  385. ================
  386. FireBullets
  387.  
  388. Used by shotgun, super shotgun, and enemy soldier firing
  389. Go to the trouble of combining multiple pellets into a single damage call.
  390. ================
  391. */
  392. void(float shotcount, vector dir, vector spread) FireBullets =
  393. {
  394.     local    vector direction;
  395.     local    vector    src;
  396.     
  397.     makevectors(self.v_angle);
  398.  
  399.     src = self.origin + v_forward*10;
  400.     src_z = self.absmin_z + self.size_z * 0.7;
  401.  
  402.     ClearMultiDamage ();
  403.     while (shotcount > 0)
  404.     {
  405.         direction = dir + crandom()*spread_x*v_right + crandom()*spread_y*v_up;
  406.  
  407.         traceline (src, src + direction*2048, FALSE, self);
  408.         if (trace_fraction != 1.0)
  409.             TraceAttack (4, direction);
  410.  
  411.         shotcount = shotcount - 1;
  412.     }
  413.     ApplyMultiDamage ();
  414. };
  415.  
  416.  
  417.  
  418. void() holy_touch =
  419. {
  420.     local string s;
  421.     if ((other.classname != "player") ||
  422.         (other.rune_num == ITEM_RUNE_VIKING))
  423.     {
  424.         remove(self);
  425.         return;
  426.     }
  427.  
  428.     if ((other.team == self.owner.team) && (other.health<100))
  429.     {
  430.         other.health = other.health + 30;
  431.         if (other.health > 100) other.health = 100;
  432.         clientmsg(other, "You have been blessed by the priest.\n");
  433.         sprint(self.owner, "Priest: Name: ");
  434.         sprint(self.owner, other.netname);
  435.         sprint(self.owner, " Health: ");
  436.         s=ftos(other.health);
  437.         sprint(self.owner, s);
  438.     }
  439.  
  440.     if ((other.team != self.owner.team) && (other.rune_num == ITEM_RUNE_VAMPIRE))
  441.     {    other.deathweapon = "holywater";
  442.         T_Damage(other, self, self.owner, 125);
  443.         other.deathweapon = ""; 
  444.         other.msg_center=1;
  445.         clientmsg(other, "The holy water burns you!\n");
  446.         self.msg_center=1;
  447.         clientmsg(self.owner, "You burn the vampire with your holy water!\n");
  448.     }
  449.  
  450.     if ((other.team != self.owner.team) &&
  451.         (other.rune_num == ITEM_RUNE_WEREWOLF))
  452.     {
  453.  
  454.         other.deathweapon="holywater";
  455.         T_Damage(other, self, self.owner, 50);
  456.         other.deathweapon = ""; 
  457.     }    
  458.  
  459.     if (other.team != self.owner.team)
  460.     {
  461.         other.deathweapon="holywater";
  462.         T_Damage(other, self, self.owner, 25);
  463.         other.deathweapon = ""; 
  464.     }
  465.     
  466.  
  467.     remove(self);
  468. };
  469.  
  470. void() W_FireHolyWater =
  471. {
  472.     local vector dir;
  473.     local entity wat;    
  474.  
  475.     dir=aim(self, 1000);
  476.     wat = spawn ();
  477.     wat.owner = self;
  478.     wat.movetype = MOVETYPE_FLYMISSILE;
  479.     wat.solid = SOLID_BBOX;
  480.  
  481.     wat.angles = vectoangles(dir);
  482.     
  483.     wat.touch = holy_touch;
  484.     wat.classname = "holywater";
  485.     wat.think = SUB_Remove;
  486.     wat.nextthink = time + 6;
  487.     setmodel (wat, "progs/s_bubble.spr");
  488.         setsize (wat, VEC_ORIGIN, VEC_ORIGIN);
  489.     setorigin (wat, self.origin+'0 0 16');
  490.     wat.velocity = dir * 1000;
  491. };
  492.  
  493. /*
  494. ================
  495. W_FireShotgun
  496. ================
  497. */
  498. void() W_FireShotgun =
  499. {
  500.     local vector dir;
  501.     local    vector    src;
  502.     local vector org;
  503.     local vector foo;
  504.     local entity e;
  505.  
  506.     if ((self.rune_num == ITEM_RUNE_PRIEST)     && (self.holy == 1))
  507.     {
  508.         W_FireHolyWater();
  509.         return;
  510.     }
  511.  
  512.     playsound (self, CHAN_WEAPON, "weapons/guncock.wav", 1, ATTN_NORM);    
  513.  
  514.     self.punchangle_x = -2;
  515.     
  516.     self.currentammo = self.ammo_shells = self.ammo_shells - 1;
  517.     dir = aim (self, 100000);
  518.     if (self.rune_num == ITEM_RUNE_NINJA)
  519.     {
  520.         if (self.player_flag & ITEM_ENEMY_FLAG)
  521.                 {
  522.                         FireBullets(6,dir, '0.04 0.04 0');
  523.                         return;
  524.                 }
  525.                 src = self.origin + v_forward*10;
  526.                 traceline (src, src + dir*2048, FALSE, self);
  527.                 if (!trace_ent.takedamage)
  528.                 {
  529.                         makevectors(dir);
  530.                         org=self.origin-trace_endpos;
  531.                         foo=normalize(org);
  532.                         org=trace_endpos+(foo*55);
  533.                         spawn_tfog(self.origin);
  534.                         spawn_tfog(self.origin);
  535.                         spawn_tfog(org);
  536.                         spawn_tfog(org);
  537.                         spawn_tdeath (org,self);
  538.                         setorigin (self, org);
  539.                         self.teleport_time = time + 1;
  540.                         self.flags = self.flags - self.flags & FL_ONGROUND;
  541.                         self.ideal_yaw=vectoyaw(self.angles);
  542.                         self.ideal_yaw=self.ideal_yaw+180;
  543.                         ChangeYaw();
  544.             self.currentammo = self.ammo_shells = self.ammo_shells + 1;
  545.                 }
  546.                 else
  547.                         FireBullets(6, dir, '0.04 0.04 0');
  548.  
  549.     }
  550.     else
  551.  
  552.     FireBullets (6, dir, '0.04 0.04 0');
  553. };
  554.  
  555.  
  556. /*
  557. ================
  558. W_FireSuperShotgun
  559. ================
  560. */
  561. void() W_FireSuperShotgun =
  562. {
  563.     local vector dir;
  564.  
  565.     if (self.currentammo == 1)
  566.     {
  567.         W_FireShotgun ();
  568.         return;
  569.     }
  570.         
  571.     playsound (self ,CHAN_WEAPON, "weapons/shotgn2.wav", 1, ATTN_NORM);    
  572.  
  573.     self.punchangle_x = -4;
  574.     
  575.     self.currentammo = self.ammo_shells = self.ammo_shells - 2;
  576.     dir = aim (self, 100000);
  577.     FireBullets (14, dir, '0.14 0.08 0');
  578. };
  579.  
  580.  
  581. /*
  582. ==============================================================================
  583.  
  584. ROCKETS
  585.  
  586. ==============================================================================
  587. */
  588.  
  589. void()    s_explode1    =    [0,        s_explode2] {};
  590. void()    s_explode2    =    [1,        s_explode3] {};
  591. void()    s_explode3    =    [2,        s_explode4] {};
  592. void()    s_explode4    =    [3,        s_explode5] {};
  593. void()    s_explode5    =    [4,        s_explode6] {};
  594. void()    s_explode6    =    [5,        SUB_Remove] {};
  595.  
  596. void() BecomeExplosion =
  597. {
  598.     self.movetype = MOVETYPE_NONE;
  599.     self.velocity = '0 0 0';
  600.     self.touch = SUB_Null;
  601.     setmodel (self, "progs/s_explod.spr");
  602.     self.solid = SOLID_NOT;
  603.     s_explode1 ();
  604. };
  605.  
  606. void() T_MissileTouch =
  607. {
  608.     local float    damg;
  609.  
  610.     if (other == self.owner)
  611.         return;        // don't explode on owner
  612.  
  613.     if (pointcontents(self.origin) == CONTENT_SKY)
  614.     {
  615.         remove(self);
  616.         return;
  617.     }
  618.  
  619.     damg = 100 + random()*20;
  620.  
  621.     if (self.owner.rune_num == ITEM_RUNE_SAMURAI)
  622.         damg = damg / 4;
  623.     
  624.     if (other.health)
  625.         T_Damage (other, self, self.owner, damg);
  626.  
  627.     // don't do radius damage to the other, because all the damage
  628.     // was done in the impact
  629.     T_RadiusDamage (self, self.owner, 120, other);
  630.  
  631. //    playsound (self, CHAN_WEAPON, "weapons/r_exp3.wav", 1, ATTN_NORM);
  632.     self.origin = self.origin - 8*normalize(self.velocity);
  633.  
  634.     WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  635.     WriteByte (MSG_BROADCAST, TE_EXPLOSION);
  636.     WriteCoord (MSG_BROADCAST, self.origin_x);
  637.     WriteCoord (MSG_BROADCAST, self.origin_y);
  638.     WriteCoord (MSG_BROADCAST, self.origin_z);
  639.  
  640.     BecomeExplosion ();
  641. };
  642.  
  643.  
  644.  
  645. /*
  646. ================
  647. W_FireRocket
  648. ================
  649. */
  650. void() W_FireRocket =
  651. {
  652.     local    entity missile, mpuff;
  653.     local vector dir;
  654.  
  655.     if (self.rune_num == ITEM_RUNE_GOLOM)
  656.         return;
  657.     self.currentammo = self.ammo_rockets = self.ammo_rockets - 1;
  658.  
  659.     playsound (self, CHAN_WEAPON, "weapons/sgun1.wav", 1, ATTN_NORM);
  660.  
  661.     self.punchangle_x = -2;
  662.  
  663.     missile = spawn ();
  664.     missile.owner = self;
  665.     missile.movetype = MOVETYPE_FLYMISSILE;
  666.     missile.solid = SOLID_BBOX;
  667.     missile.classname = "missile";
  668.         
  669. // set missile speed    
  670.  
  671.     makevectors (self.v_angle);
  672.     missile.velocity = aim(self, 100000);
  673.     if (self.rune_num == ITEM_RUNE_WIND)    
  674.         missile.velocity = missile.velocity * 3000;
  675.     else
  676.         missile.velocity = missile.velocity * 1000;
  677.     missile.angles = vectoangles(missile.velocity);
  678.     
  679.     missile.touch = T_MissileTouch;
  680.     
  681. // set missile duration
  682.     missile.nextthink = time + 5;
  683.     missile.think = SUB_Remove;
  684.  
  685.     if (self.rune_num != ITEM_RUNE_LOKI)
  686.         setmodel (missile, "progs/missile.mdl");
  687.     setsize (missile, '0 0 0', '0 0 0');        
  688.     setorigin (missile, self.origin + v_forward*8 + '0 0 16');
  689.     if ((self.rune_num == ITEM_RUNE_VAMPIRE) ||
  690.             (self.rune_num == ITEM_RUNE_IFRITE))
  691.     {
  692.         dir = aim (self, 1000);
  693.         launch_spike(self.origin + '0 0 16', dir);
  694.         newmis.solid=SOLID_NOT;
  695.         newmis.nextthink=time+3;
  696.         if (self.rune_num == ITEM_RUNE_VAMPIRE)
  697.             setmodel(newmis, "progs/w_spike.mdl");
  698.         else
  699.             setmodel(newmis, "progs/k_spike.mdl");
  700.         setsize(newmis, VEC_ORIGIN, VEC_ORIGIN);
  701.         launch_spike(self.origin - '0 0 16', dir);
  702.         newmis.solid=SOLID_NOT;
  703.         newmis.nextthink=time+3;
  704.         if (self.rune_num == ITEM_RUNE_VAMPIRE)
  705.             setmodel(newmis, "progs/w_spike.mdl");
  706.         else
  707.             setmodel(newmis, "progs/k_spike.mdl");
  708.         setsize(newmis, VEC_ORIGIN, VEC_ORIGIN);
  709.     }
  710.     else if (self.rune_num == ITEM_RUNE_PRIEST)
  711.     {
  712.         dir=aim(self, 1000);
  713.         launch_spike(self.origin + '0 0 16', dir);
  714.         newmis.nextthink=time+5;
  715.         newmis.touch=holy_touch;
  716.         setmodel(newmis, "progs/s_bubble.spr");
  717.         setsize(newmis, VEC_ORIGIN, VEC_ORIGIN);
  718.         newmis.velocity=newmis.velocity - (newmis.velocity * 0.1);
  719.         launch_spike(self.origin + '0 0 16', dir);
  720.         newmis.nextthink=time+5;
  721.         newmis.touch=holy_touch;
  722.         setmodel(newmis, "progs/s_bubble.spr");
  723.         setsize(newmis, VEC_ORIGIN, VEC_ORIGIN);
  724.         newmis.velocity=newmis.velocity - (newmis.velocity * 0.2);
  725.         launch_spike(self.origin + '0 0 16', dir);
  726.         newmis.nextthink=time+5;
  727.         newmis.touch=holy_touch;
  728.         setmodel(newmis, "progs/s_bubble.spr");
  729.         setsize(newmis, VEC_ORIGIN, VEC_ORIGIN);
  730.         newmis.velocity=newmis.velocity - (newmis.velocity * 0.3);
  731.         launch_spike(self.origin + '0 0 16', dir);
  732.         newmis.nextthink=time+5;
  733.         newmis.touch=holy_touch;
  734.         setmodel(newmis, "progs/s_bubble.spr");
  735.         setsize(newmis, VEC_ORIGIN, VEC_ORIGIN);
  736.         newmis.velocity=newmis.velocity - (newmis.velocity * 0.8);
  737.         launch_spike(self.origin + '0 0 16', dir);
  738.         newmis.nextthink=time+5;
  739.         newmis.touch=holy_touch;
  740.         setmodel(newmis, "progs/s_bubble.spr");
  741.         setsize(newmis, VEC_ORIGIN, VEC_ORIGIN);
  742.         newmis.velocity=newmis.velocity - (newmis.velocity * 0.82);
  743.     }
  744. };
  745.  
  746. /*
  747. ===============================================================================
  748.  
  749. LIGHTNING
  750.  
  751. ===============================================================================
  752. */
  753.  
  754. /*
  755. =================
  756. LightningDamage
  757. =================
  758. */
  759. void(vector p1, vector p2, entity from, float damage) LightningDamage =
  760. {
  761.     local entity        e1, e2;
  762.     local vector        f, v;
  763.     
  764.     f = p2 - p1;
  765.     normalize (f);
  766.     f_x = 0 - f_y;
  767.     f_y = f_x;
  768.     f_z = 0;
  769.     f = f*16;
  770.  
  771.     e1 = e2 = world;
  772.  
  773.     traceline (p1, p2, FALSE, self);
  774.  
  775.     if (trace_ent.takedamage)
  776.     {
  777.         particle (trace_endpos, '0 0 100', 225, damage*4);
  778.         T_Damage (trace_ent, from, from, damage);
  779.         if (self.classname == "player")
  780.         {
  781.             if (other.classname == "player")
  782.                 trace_ent.velocity_z = trace_ent.velocity_z + 400;
  783.         }
  784.     }
  785.     e1 = trace_ent;
  786.  
  787.     traceline (p1 + f, p2 + f, FALSE, self);
  788.  
  789.     if (trace_ent != e1 && trace_ent.takedamage)
  790.     {
  791.         particle (trace_endpos, '0 0 100', 225, damage*4);
  792.         T_Damage (trace_ent, from, from, damage);
  793.     }
  794.     e2 = trace_ent;
  795.  
  796.     traceline (p1 - f, p2 - f, FALSE, self);
  797.  
  798.     if (trace_ent != e1 && trace_ent != e2 && trace_ent.takedamage)
  799.     {
  800.         particle (trace_endpos, '0 0 100', 225, damage*4);
  801.         T_Damage (trace_ent, from, from, damage);
  802.     }
  803. };
  804.  
  805.  
  806.  
  807. void(vector p1, vector p2, entity from, float damage) TractorEffect =
  808. {
  809.         local entity            e1, e2;
  810.         local vector            f;
  811.  
  812.         f = p2 - p1;
  813.         normalize (f);
  814.         f_x = 0 - f_y;
  815.         f_y = f_x;
  816.         f_z = 0;
  817.         f = f*16;
  818.  
  819.         e1 = e2 = world;
  820.  
  821.         traceline (p1, p2, FALSE, self);
  822.         e1 = trace_ent;
  823.         if (trace_ent.takedamage && trace_ent.classname != "trigger_multiple"&& trace_ent.classname != "door")
  824.         {
  825.                 trace_ent.origin = self.origin+v_forward*vlen(self.origin-trace_ent.origin);
  826.                 trace_ent.movetype = MOVETYPE_TOSS;
  827.                 trace_ent.nextthink = time + 0.5;
  828.         }
  829.  
  830.         traceline (p1 + f, p2 + f, FALSE, self);
  831.         if (trace_ent != e1 && trace_ent.takedamage &&
  832.     trace_ent.classname != "trigger_multiple" &&
  833.     trace_ent.classname != "door")
  834.         {
  835.                 trace_ent.origin = self.origin+v_forward*vlen(self.origin-trace_ent.origin);
  836.                 trace_ent.movetype = MOVETYPE_TOSS;
  837.                 trace_ent.nextthink = time + 0.5;
  838.         }
  839.         e2 = trace_ent;
  840.  
  841.         traceline (p1 - f, p2 - f, FALSE, self);
  842.         if (trace_ent.takedamage && trace_ent != e1 && trace_ent != e2 && trace_ent.classname != "trigger_multiple" && trace_ent.classname != "door")
  843.         {
  844.                 trace_ent.origin = self.origin+v_forward*vlen(self.origin-trace_ent.origin);
  845.                 trace_ent.movetype = MOVETYPE_TOSS;
  846.                 trace_ent.nextthink = time + 0.5;
  847.         }
  848. };
  849.  
  850.  
  851. void(vector v) ThorBoilWaterPoint =
  852. {
  853.     local entity bubble;
  854.  
  855.  
  856.     // SUCK: Spawn some bubbles to make it look like the water is
  857.     // boiling.        
  858.     bubble=spawn();
  859.     setmodel(bubble, "progs/s_bubble.spr");
  860.     setorigin(bubble, v);
  861.     bubble.movetype=MOVETYPE_NOCLIP;
  862.     bubble.solid = SOLID_NOT;
  863.     bubble.velocity_z=45;
  864.     bubble.velocity_x=(random()*100) - 50;
  865.     bubble.velocity_y=(random()*100) - 50;
  866.     bubble.nextthink = time + 1.5;
  867.     bubble.think = SUB_Remove;
  868.     bubble.classname = "bubble";
  869.     bubble.frame = 0;
  870.     bubble.cnt = 0;
  871.     setsize(bubble, '-8 -8 -8', '8 8 8');
  872.     bubble=spawn();
  873.     setmodel(bubble, "progs/s_bubble.spr");
  874.     setorigin(bubble, v);
  875.     bubble.movetype=MOVETYPE_NOCLIP;
  876.     bubble.solid = SOLID_NOT;
  877.     bubble.velocity_z=45;
  878.     bubble.velocity_x=(random()*100) - 50;
  879.     bubble.velocity_y=(random()*100) - 50;
  880.     bubble.nextthink = time + 1.5;
  881.     bubble.think = SUB_Remove;
  882.     bubble.classname = "bubble";
  883.     bubble.frame = 0;
  884.     bubble.cnt = 0;
  885.     setsize(bubble, '-8 -8 -8', '8 8 8');
  886.  
  887. }; 
  888.  
  889. void(vector org) ThorBoilWater =
  890. {
  891.     local vector v;
  892.     local float f;
  893.     local float num_bubbles;
  894.     local entity e;
  895.  
  896.     v=v_forward*600;
  897.     v=normalize(v);
  898.  
  899.     if (self.rune_time < time)
  900.         num_bubbles=0;
  901.     else
  902.         num_bubbles=1000;
  903.     f=30;
  904.     while (f<600)
  905.     {
  906.         if ((pointcontents(org+(v*f))==CONTENT_WATER) ||
  907.         (pointcontents(org+(v*f))==CONTENT_SLIME))
  908.         {
  909.             if (num_bubbles<6)
  910.             {
  911.                 ThorBoilWaterPoint(org+(v*f));
  912.                 self.rune_time = time+1.5;
  913.             }
  914.             num_bubbles = num_bubbles + 1;
  915.             // SUCK: Hurt any enemies near the boiling water
  916.             e=findradius((v*f)+org, 75);
  917.             while (e!=world)
  918.             {
  919.                 if ((e.classname == "player") &&
  920.                     (e.team != self.team))
  921.                     T_Damage(e, self, self, 5);
  922.                 e=e.chain;
  923.             }
  924.         }
  925.         f=f+30;
  926.     }
  927. };
  928.  
  929. void() W_FireLightning =
  930. {
  931.     local    vector        org;
  932.     local    float        cells;
  933.     local entity kam;
  934.     local vector v;
  935.     local float r,q;
  936.  
  937.     if (self.rune_num == ITEM_RUNE_GOLOM)
  938.         return;
  939.     
  940.     if (self.ammo_cells < 1)
  941.     {
  942.         self.weapon = W_BestWeapon ();
  943.         W_SetCurrentAmmo ();
  944.         return;
  945.     }
  946.  
  947.     if ((self.rune_num == ITEM_RUNE_THOR) && (self.rune_sound_start<time))
  948.     {
  949.         sound(self, CHAN_BODY, "ambience/thunder1.wav", 1, ATTN_NORM);
  950.         self.rune_sound_start=time+3.75;
  951.     }
  952.  
  953.  
  954. // explode if under water
  955.     if ((self.waterlevel > 1) && (self.rune_num != ITEM_RUNE_THOR) &&
  956.         !((self.rune_num == ITEM_RUNE_HERMES) && (self.last_flight_watertype==CONTENT_EMPTY)) && (self.rune_num != ITEM_RUNE_POSEIDON))
  957.     {
  958.         cells = self.ammo_cells;
  959.         self.ammo_cells = 0;
  960.         W_SetCurrentAmmo ();
  961.         T_DischargeDamage (self, self, 35*cells, world);
  962.         return;
  963.     }
  964.  
  965.     if (self.t_width < time)
  966.     {
  967.         playsound (self, CHAN_WEAPON, "weapons/lhit.wav", 1, ATTN_NORM);
  968.         self.t_width = time + 0.6;
  969.     }
  970.     self.punchangle_x = -2;
  971.  
  972.     if (self.rune_num != ITEM_RUNE_THOR)
  973.         self.currentammo = self.ammo_cells = self.ammo_cells - 1;
  974.     else if ((self.rune_num == ITEM_RUNE_POSEIDON) &&
  975.         (self.ammo_cells == 100))
  976.     {    
  977.         self.currentammo = self.ammo_cells = self.ammo_cells - 4;
  978.         self.trident_time = time + 3;
  979.     }    
  980.  
  981.     org = self.origin + '0 0 16';
  982.     
  983.     traceline (org, org + v_forward*600, TRUE, self);
  984.  
  985.     // SUCK: Boil the water that the shaft touches, if it does.
  986.     if (self.rune_num == ITEM_RUNE_THOR)
  987.         ThorBoilWater(org);
  988.  
  989.     WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  990.     WriteByte (MSG_BROADCAST, TE_LIGHTNING2);
  991.     WriteEntity (MSG_BROADCAST, self);
  992.     WriteCoord (MSG_BROADCAST, org_x);
  993.     WriteCoord (MSG_BROADCAST, org_y);
  994.     WriteCoord (MSG_BROADCAST, org_z);
  995.     WriteCoord (MSG_BROADCAST, trace_endpos_x);
  996.     WriteCoord (MSG_BROADCAST, trace_endpos_y);
  997.     WriteCoord (MSG_BROADCAST, trace_endpos_z);
  998.  
  999.     if (self.rune_num == ITEM_RUNE_THOR)
  1000.         LightningDamage (self.origin, trace_endpos + v_forward*4, self, 25);
  1001.     else if ((self.rune_num == ITEM_RUNE_POSEIDON) && (self.trident_time>time))
  1002.         LightningDamage (self.origin, trace_endpos + v_forward*4, self, 60);
  1003.     else
  1004.         LightningDamage (self.origin, trace_endpos + v_forward*4, self, 30);            
  1005.  
  1006.  
  1007. };
  1008.  
  1009.  
  1010. //=============================================================================
  1011.  
  1012.  
  1013. void() GrenadeExplode =
  1014. {
  1015.     if (self.owner.rune_num == ITEM_RUNE_SAMURAI)
  1016.         T_RadiusDamage (self, self.owner, 30, world);
  1017.     else
  1018.         T_RadiusDamage (self, self.owner, 120, world);
  1019.     
  1020. //        playsound (self, CHAN_WEAPON, "dog/ddeath.wav", 1, ATTN_NORM);
  1021.  
  1022.  
  1023.     WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  1024.     WriteByte (MSG_BROADCAST, TE_EXPLOSION);
  1025.     WriteCoord (MSG_BROADCAST, self.origin_x);
  1026.     WriteCoord (MSG_BROADCAST, self.origin_y);
  1027.     WriteCoord (MSG_BROADCAST, self.origin_z);
  1028.  
  1029.     BecomeExplosion ();
  1030. };
  1031.  
  1032. void() GrenadeTouch =
  1033. {
  1034.     if (other == self.owner)
  1035.         return;        // don't explode on owner
  1036.     if (other.takedamage == DAMAGE_AIM)
  1037.     {
  1038.  
  1039.         GrenadeExplode();
  1040.         return;
  1041.     }
  1042.     playsound (self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM);    // bounce sound
  1043.     if (self.velocity == '0 0 0')
  1044.         self.avelocity = '0 0 0';
  1045. };
  1046.  
  1047. /*
  1048. ================
  1049. W_FireGrenade
  1050. ================
  1051. */
  1052. void() W_FireGrenade =
  1053. {
  1054.     local    entity missile, mpuff;
  1055.  
  1056.     if (self.rune_num == ITEM_RUNE_GOLOM)
  1057.         return;
  1058.  
  1059.     self.currentammo = self.ammo_rockets = self.ammo_rockets - 1;
  1060.  
  1061.     
  1062.     playsound (self, CHAN_WEAPON, "weapons/grenade.wav", 1, ATTN_NORM);
  1063.  
  1064.     self.punchangle_x = -2;
  1065.  
  1066.     missile = spawn ();
  1067.     missile.owner = self;
  1068.     missile.movetype = MOVETYPE_BOUNCE;
  1069.     missile.solid = SOLID_BBOX;
  1070.     missile.classname = "grenade";
  1071.         
  1072. // set missile speed    
  1073.  
  1074.     makevectors (self.v_angle);
  1075.  
  1076.     if (self.v_angle_x)
  1077.         missile.velocity = v_forward*600 + v_up * 200 + crandom()*v_right*10 + crandom()*v_up*10;
  1078.     else
  1079.     {
  1080.         missile.velocity = aim(self, 10000);
  1081.         missile.velocity = missile.velocity * 600;
  1082.         missile.velocity_z = 200;
  1083.     }
  1084.  
  1085.     missile.avelocity = '300 300 300';
  1086.  
  1087.     missile.angles = vectoangles(missile.velocity);
  1088.     
  1089.     missile.touch = GrenadeTouch;
  1090.     
  1091. // set missile duration
  1092.     missile.nextthink = time + missile.owner.grenade_time;
  1093.     if (self.grenade_time != 2.5) self.grenade_time = 2.5;
  1094.     missile.think = GrenadeExplode;
  1095.  
  1096. //        playsound (self, CHAN_WEAPON, "dog/dsight.wav", 1, ATTN_NORM);
  1097.     setmodel (missile, "progs/grenade.mdl");
  1098. //    setmodel (missile, "progs/dog.mdl");
  1099.  
  1100.     setsize (missile, '0 0 0', '0 0 0');        
  1101.     setorigin (missile, self.origin);
  1102. };
  1103.  
  1104.  
  1105. //=============================================================================
  1106.  
  1107. void() spike_touch;
  1108. void() superspike_touch;
  1109.  
  1110.  
  1111. /*
  1112. ===============
  1113. launch_spike
  1114.  
  1115. Used for both the player and the ogre
  1116. ===============
  1117. */
  1118. void(vector org, vector dir) launch_spike =
  1119. {
  1120.     newmis = spawn ();
  1121.     newmis.owner = self;
  1122.     newmis.movetype = MOVETYPE_FLYMISSILE;
  1123.     newmis.solid = SOLID_BBOX;
  1124.  
  1125.     newmis.angles = vectoangles(dir);
  1126.     
  1127.     newmis.touch = spike_touch;
  1128.     newmis.classname = "spike";
  1129.     newmis.think = SUB_Remove;
  1130.     newmis.nextthink = time + 6;
  1131.     if (self.rune_num != ITEM_RUNE_LOKI)
  1132.         setmodel (newmis, "progs/spike.mdl");
  1133.      setsize (newmis, VEC_ORIGIN, VEC_ORIGIN);        
  1134.     setorigin (newmis, org);
  1135.     if (self.rune_num == ITEM_RUNE_WIND)
  1136.         newmis.velocity = dir * 3000;
  1137.     else
  1138.         newmis.velocity = dir * 1000;
  1139. };
  1140.  
  1141. void() W_FireSuperSpikes =
  1142. {
  1143.     local vector    dir;
  1144.     local entity    old;
  1145.     
  1146.     playsound (self, CHAN_WEAPON, "weapons/spike2.wav", 1, ATTN_NORM);
  1147.     self.attack_finished = time + 0.2 + self.balder_slowdown;
  1148.     self.currentammo = self.ammo_nails = self.ammo_nails - 2;
  1149.     dir = aim (self, 1000);
  1150.     launch_spike (self.origin + '0 0 16', dir);
  1151.     newmis.touch = superspike_touch;
  1152.     if (self.rune_num != ITEM_RUNE_LOKI)
  1153.         setmodel (newmis, "progs/s_spike.mdl");
  1154.     setsize (newmis, VEC_ORIGIN, VEC_ORIGIN);        
  1155.     self.punchangle_x = -2;
  1156.     if ((self.rune_num == ITEM_RUNE_VAMPIRE)||
  1157.             (self.rune_num == ITEM_RUNE_IFRITE))
  1158.     {
  1159.         launch_spike(self.origin + '0 0 16', dir);
  1160.         newmis.solid=SOLID_NOT;
  1161.         newmis.nextthink=time+3;
  1162.         if (self.rune_num == ITEM_RUNE_VAMPIRE)
  1163.             setmodel(newmis, "progs/w_spike.mdl");
  1164.         else
  1165.             setmodel(newmis, "progs/k_spike.mdl");
  1166.         setsize(newmis, VEC_ORIGIN, VEC_ORIGIN);
  1167.     }
  1168.     else if (self.rune_num == ITEM_RUNE_PRIEST)
  1169.     {
  1170.         launch_spike(self.origin + '0 0 16', dir);
  1171.         newmis.nextthink=time+5;
  1172.         newmis.touch=holy_touch;
  1173.         newmis.velocity=newmis.velocity - (newmis.velocity * 0.1);
  1174.         setmodel(newmis, "progs/s_bubble.spr");
  1175.         setsize(newmis, VEC_ORIGIN, VEC_ORIGIN);
  1176.     }
  1177. };
  1178.  
  1179. void(float ox) W_FireSpikes =
  1180. {
  1181.     local vector    dir;
  1182.     local entity    old;
  1183.     
  1184.     makevectors (self.v_angle);
  1185.     
  1186.     if (self.ammo_nails >= 2 && self.weapon == IT_SUPER_NAILGUN)
  1187.     {
  1188.         W_FireSuperSpikes ();
  1189.         return;
  1190.     }
  1191.  
  1192.     if (self.ammo_nails < 1)
  1193.     {
  1194.         self.weapon = W_BestWeapon ();
  1195.         W_SetCurrentAmmo ();
  1196.         return;
  1197.     }
  1198.  
  1199.     playsound (self, CHAN_WEAPON, "weapons/rocket1i.wav", 1, ATTN_NORM);
  1200.     self.attack_finished = time + 0.2 + self.balder_slowdown;
  1201.     self.currentammo = self.ammo_nails = self.ammo_nails - 1;
  1202.     dir = aim (self, 1000);
  1203.     launch_spike (self.origin + '0 0 16' + v_right*ox, dir);
  1204.     if ((self.rune_num == ITEM_RUNE_VAMPIRE) ||
  1205.             (self.rune_num == ITEM_RUNE_IFRITE))
  1206.     {
  1207.         launch_spike(self.origin + '0 0 16', dir);
  1208.         newmis.nextthink=time+3;
  1209.         if (self.rune_num == ITEM_RUNE_VAMPIRE)
  1210.             setmodel(newmis, "progs/w_spike.mdl");
  1211.         else
  1212.             setmodel(newmis, "progs/k_spike.mdl");
  1213.         newmis.solid=SOLID_NOT;
  1214.         setsize(newmis, VEC_ORIGIN, VEC_ORIGIN);
  1215.     }
  1216.     else if (self.rune_num == ITEM_RUNE_PRIEST)
  1217.     {
  1218.         launch_spike(self.origin + '0 0 16', dir);
  1219.         newmis.nextthink=time+5;
  1220.         newmis.touch=holy_touch;
  1221.         setmodel(newmis, "progs/s_bubble.spr");
  1222.         newmis.velocity=newmis.velocity - (newmis.velocity * 0.1);
  1223.         setsize(newmis, VEC_ORIGIN, VEC_ORIGIN);
  1224.     }
  1225.     self.punchangle_x = -2;
  1226. };
  1227.  
  1228.  
  1229.  
  1230. .float hit_z;
  1231. void() spike_touch =
  1232. {
  1233. local float rand;
  1234.     if (other == self.owner)
  1235.         return;
  1236.  
  1237.     if (other.solid == SOLID_TRIGGER)
  1238.         return;    // trigger field, do nothing
  1239.  
  1240.     if (pointcontents(self.origin) == CONTENT_SKY)
  1241.     {
  1242.         remove(self);
  1243.         return;
  1244.     }
  1245.     
  1246. // hit something that bleeds
  1247.     if (other.takedamage)
  1248.     {
  1249.         spawn_touchblood (9);
  1250.         if (self.owner.rune_num == ITEM_RUNE_SAMURAI)
  1251.             T_Damage (other, self, self.owner, 18);
  1252.         else
  1253.             T_Damage (other, self, self.owner, 9);
  1254.     }
  1255.     else
  1256.     {
  1257.         WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  1258.         
  1259.         if (self.classname == "wizspike")
  1260.             WriteByte (MSG_BROADCAST, TE_WIZSPIKE);
  1261.         else if (self.classname == "knightspike")
  1262.             WriteByte (MSG_BROADCAST, TE_KNIGHTSPIKE);
  1263.         else
  1264.             WriteByte (MSG_BROADCAST, TE_SPIKE);
  1265.         WriteCoord (MSG_BROADCAST, self.origin_x);
  1266.         WriteCoord (MSG_BROADCAST, self.origin_y);
  1267.         WriteCoord (MSG_BROADCAST, self.origin_z);
  1268.     }
  1269.  
  1270.     remove(self);
  1271.  
  1272. };
  1273.  
  1274. void() superspike_touch =
  1275. {
  1276. local float rand, f;
  1277. local vector v;
  1278. local string s;    
  1279.     if (other == self.owner)
  1280.         return;
  1281.  
  1282.     if (other.solid == SOLID_TRIGGER)
  1283.         return;    // trigger field, do nothing
  1284.  
  1285.     if (pointcontents(self.origin) == CONTENT_SKY)
  1286.     {
  1287.         remove(self);
  1288.         return;
  1289.     }
  1290.     
  1291. // hit something that bleeds
  1292.     if (other.takedamage)
  1293.     {
  1294.         spawn_touchblood (18);
  1295.         v=self.origin - other.origin;
  1296.         f=vlen(v);
  1297.         s=ftos(f);
  1298.         v=other.origin - self.origin;
  1299.         v=normalize(v);
  1300.         s=vtos(v);
  1301.  
  1302.         if (self.rune_num == ITEM_RUNE_SAMURAI)
  1303.             T_Damage (other, self, self.owner, 36);
  1304.         else
  1305.             T_Damage (other, self, self.owner, 18);
  1306.     }
  1307.     else
  1308.     {
  1309.         WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  1310.         WriteByte (MSG_BROADCAST, TE_SUPERSPIKE);
  1311.         WriteCoord (MSG_BROADCAST, self.origin_x);
  1312.         WriteCoord (MSG_BROADCAST, self.origin_y);
  1313.         WriteCoord (MSG_BROADCAST, self.origin_z);
  1314.     }
  1315.  
  1316.     remove(self);
  1317.  
  1318. };
  1319.  
  1320.  
  1321. /*
  1322. ===============================================================================
  1323.  
  1324. PLAYER WEAPON USE
  1325.  
  1326. ===============================================================================
  1327. */
  1328.  
  1329. void() W_SetCurrentAmmo =
  1330. {
  1331.     player_run ();        // get out of any weapon firing states
  1332.  
  1333.     self.items = self.items - ( self.items & (IT_SHELLS | IT_NAILS | IT_ROCKETS | IT_CELLS) );
  1334.     
  1335.     if (self.weapon == IT_AXE)
  1336.     {
  1337.         self.currentammo = 0;
  1338.         self.weaponmodel = "progs/v_axe.mdl";
  1339.         self.weaponframe = 0;
  1340.     }
  1341.     else if (self.weapon == IT_HOOK)
  1342.     {
  1343.         self.currentammo = 0;
  1344.         if (teamplay & TEAM_CAPTURE_CUSTOM) 
  1345.             self.weaponmodel = "progs/v_star.mdl";
  1346.         else
  1347.             self.weaponmodel = "progs/v_axe.mdl";
  1348.         self.weaponframe = 0;
  1349.     }
  1350.     else if (self.weapon == IT_SHOTGUN)
  1351.     {
  1352.         self.currentammo = self.ammo_shells;
  1353.         self.weaponmodel = "progs/v_shot.mdl";
  1354.         self.weaponframe = 0;
  1355.         self.items = self.items | IT_SHELLS;
  1356.     }
  1357.     else if (self.weapon == IT_SUPER_SHOTGUN)
  1358.     {
  1359.         self.currentammo = self.ammo_shells;
  1360.         self.weaponmodel = "progs/v_shot2.mdl";
  1361.         self.weaponframe = 0;
  1362.         self.items = self.items | IT_SHELLS;
  1363.     }
  1364.     else if (self.weapon == IT_NAILGUN)
  1365.     {
  1366.         self.currentammo = self.ammo_nails;
  1367.         self.weaponmodel = "progs/v_nail.mdl";
  1368.         self.weaponframe = 0;
  1369.         self.items = self.items | IT_NAILS;
  1370.     }
  1371.     else if (self.weapon == IT_SUPER_NAILGUN)
  1372.     {
  1373.         self.currentammo = self.ammo_nails;
  1374.         self.weaponmodel = "progs/v_nail2.mdl";
  1375.         self.weaponframe = 0;
  1376.         self.items = self.items | IT_NAILS;
  1377.     }
  1378.     else if (self.weapon == IT_GRENADE_LAUNCHER)
  1379.     {
  1380.         self.currentammo = self.ammo_rockets;
  1381.         self.weaponmodel = "progs/v_rock.mdl";
  1382.         self.weaponframe = 0;
  1383.         self.items = self.items | IT_ROCKETS;
  1384.     }
  1385.     else if (self.weapon == IT_ROCKET_LAUNCHER)
  1386.     {
  1387.         self.currentammo = self.ammo_rockets;
  1388.         self.weaponmodel = "progs/v_rock2.mdl";
  1389.         self.weaponframe = 0;
  1390.         self.items = self.items | IT_ROCKETS;
  1391.     }
  1392.     else if (self.weapon == IT_LIGHTNING)
  1393.     {
  1394.         self.currentammo = self.ammo_cells;
  1395.         self.weaponmodel = "progs/v_light.mdl";
  1396.         self.weaponframe = 0;
  1397.         self.items = self.items | IT_CELLS;
  1398.     }
  1399.     else
  1400.     {
  1401.         self.currentammo = 0;
  1402.         self.weaponmodel = "";
  1403.         self.weaponframe = 0;
  1404.     }
  1405. };
  1406.  
  1407. float() W_BestWeapon =
  1408. {
  1409.     local    float    it;
  1410.     
  1411.     it = self.items;
  1412.  
  1413.  
  1414.     if (self.waterlevel <= 1 && self.ammo_cells >= 1 && (it & IT_LIGHTNING) )
  1415.         return IT_LIGHTNING;
  1416.     if(self.ammo_nails >= 2 && (it & IT_SUPER_NAILGUN) )
  1417.         return IT_SUPER_NAILGUN;
  1418.     if(self.ammo_shells >= 2 && (it & IT_SUPER_SHOTGUN) )
  1419.         return IT_SUPER_SHOTGUN;
  1420.     if(self.ammo_nails >= 1 && (it & IT_NAILGUN) )
  1421.         return IT_NAILGUN;
  1422.     if(self.ammo_shells >= 1 && (it & IT_SHOTGUN) )
  1423.         return IT_SHOTGUN;
  1424.     return IT_AXE;
  1425. };
  1426.  
  1427. float() W_CheckNoAmmo =
  1428. {
  1429.     if (self.currentammo > 0)
  1430.         return TRUE;
  1431.  
  1432.     if (self.weapon == IT_AXE || self.weapon == IT_HOOK)
  1433.         return TRUE;
  1434.     
  1435.     self.weapon = W_BestWeapon ();
  1436.  
  1437.     W_SetCurrentAmmo ();
  1438.     
  1439. // drop the weapon down
  1440.     return FALSE;
  1441. };
  1442.  
  1443. /*
  1444. ============
  1445. W_Attack
  1446.  
  1447. An attack impulse can be triggered now
  1448. ============
  1449. */
  1450. void()    player_axe1;
  1451. void()    player_axeb1;
  1452. void()    player_axec1;
  1453. void()    player_axed1;
  1454. void()    player_shot1;
  1455. void()    player_nail1;
  1456. void()    player_light1;
  1457. void()    player_rocket1;
  1458. void()    player_chain1;
  1459. void()  player_chain3;
  1460.  
  1461. void() W_Attack =
  1462. {
  1463.     local    float    r;
  1464.  
  1465.     if (!W_CheckNoAmmo ())
  1466.         return;
  1467.  
  1468.     if (self.loki_possessed)
  1469.         return;
  1470.     if (self.rune_num == ITEM_RUNE_LOKI)
  1471.         self.loki_forcevis = 1;
  1472.  
  1473.     makevectors    (self.v_angle);            // calculate forward angle for velocity
  1474.     self.show_hostile = time + 1;    // wake monsters up
  1475.  
  1476.     if (self.attack_finished > time)
  1477.         return;
  1478.  
  1479.     if (self.weapon == IT_AXE)
  1480.     {
  1481.         playsound (self, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM);
  1482.         r = random();
  1483.         if (r < 0.25)
  1484.             player_axe1 ();
  1485.         else if (r<0.5)
  1486.             player_axeb1 ();
  1487.         else if (r<0.75)
  1488.             player_axec1 ();
  1489.         else
  1490.             player_axed1 ();
  1491.         // RUNE: rune of hell magic
  1492.         if (self.rune_num == ITEM_RUNE_HASTE) {
  1493.             self.attack_finished = time + 0.3 + self.balder_slowdown;
  1494.             HasteSound();
  1495.         } else
  1496.             self.attack_finished = time + 0.5 + self.balder_slowdown;
  1497.     }
  1498.     else if (self.weapon == IT_SHOTGUN)
  1499.     {
  1500.         player_shot1 ();
  1501.         W_FireShotgun ();
  1502.         // RUNE: rune of hell magic
  1503.         if (self.rune_num == ITEM_RUNE_HASTE) {
  1504.             self.attack_finished = time + 0.3 + self.balder_slowdown;
  1505.             HasteSound();
  1506.         } else
  1507.         self.attack_finished = time + 0.5 + self.balder_slowdown;
  1508.         if ((self.rune_num == ITEM_RUNE_PRIEST) && (self.holy == 1))
  1509.             self.attack_finished=time+0.2 + self.balder_slowdown;
  1510.     }
  1511.     else if (self.weapon == IT_SUPER_SHOTGUN)
  1512.     {
  1513.         player_shot1 ();
  1514.         W_FireSuperShotgun ();
  1515.         // RUNE: rune of hell magic
  1516.         if (self.rune_num == ITEM_RUNE_HASTE)
  1517.         {
  1518.             self.attack_finished = time + 0.4 + self.balder_slowdown;
  1519.             HasteSound();
  1520.         }
  1521.         else    
  1522.             self.attack_finished = time + 0.7 + self.balder_slowdown;
  1523.  
  1524.  
  1525.     }
  1526.     else if (self.weapon == IT_NAILGUN)
  1527.     {
  1528.         player_nail1 ();
  1529.     }
  1530.     else if (self.weapon == IT_SUPER_NAILGUN)
  1531.     {
  1532.         player_nail1 ();
  1533.     }
  1534.     else if (self.weapon == IT_GRENADE_LAUNCHER)
  1535.     {
  1536.         player_rocket1();
  1537.         W_FireGrenade();
  1538.         // RUNE: rune of hell magic
  1539.         if (self.rune_num == ITEM_RUNE_HASTE) {
  1540.             self.attack_finished = time + 0.3 + self.balder_slowdown;
  1541.             HasteSound();
  1542.         } else
  1543.             self.attack_finished = time + 0.6 + self.balder_slowdown;
  1544.     }
  1545.     else if (self.weapon == IT_ROCKET_LAUNCHER)
  1546.     {
  1547.         player_rocket1();
  1548.         W_FireRocket();
  1549.         // RUNE: rune of hell magic
  1550.         if (self.rune_num == ITEM_RUNE_HASTE) {
  1551.             self.attack_finished = time + 0.4 + self.balder_slowdown;
  1552.             HasteSound();
  1553.         } else
  1554.             self.attack_finished = time + 0.8 + self.balder_slowdown;
  1555.     }
  1556.     else if (self.weapon == IT_LIGHTNING)
  1557.     {
  1558.         player_light1();
  1559.         self.attack_finished = time + 0.1 + self.balder_slowdown;
  1560.         playsound (self, CHAN_AUTO, "weapons/lstart.wav", 1, ATTN_NORM);
  1561.     }
  1562.     else if (self.weapon == IT_HOOK)
  1563.     {
  1564.         if (!self.hook_out)
  1565.             player_chain1();
  1566.         else
  1567.             player_chain3();
  1568.         self.attack_finished = time + 0.1 + self.balder_slowdown;
  1569.     }
  1570. };
  1571.  
  1572. void() NotifyWeapon =
  1573. {
  1574. //    if (self.weapon == IT_AXE)
  1575. //        sprint(self, "Axe selected.\n");
  1576. //    else if (self.weapon == IT_HOOK)
  1577. //        sprint(self, "Grappling hook selected.\n");
  1578. };
  1579.  
  1580. void(float fl, float am) forge_ammo =
  1581. {
  1582.     if (self.armorvalue<20)
  1583.     {
  1584.         clientmsg(self, "Not enough armor to forge ammo.\n");
  1585.         return;
  1586.     }
  1587.     self.armorvalue = self.armorvalue - 20;
  1588.     if ((fl == IT_SUPER_SHOTGUN) || (fl == IT_SHOTGUN))
  1589.         self.ammo_shells = self.ammo_shells + 20;
  1590.     if ((fl == IT_NAILGUN) || (fl == IT_SUPER_NAILGUN))
  1591.         self.ammo_nails = self.ammo_nails + 20;
  1592.     if ((fl == IT_GRENADE_LAUNCHER) || (fl == IT_ROCKET_LAUNCHER))
  1593.         self.ammo_rockets = self.ammo_rockets + 2;
  1594.     if (fl == IT_LIGHTNING)
  1595.         self.ammo_cells = self.ammo_cells + 10;
  1596.     if (self.ammo_shells > 100) self.ammo_shells = 100;
  1597.     if (self.ammo_nails > 200) self.ammo_nails = 200;
  1598.     if (self.ammo_rockets > 100) self.ammo_rockets = 100;
  1599.     if (self.ammo_cells > 100) self.ammo_cells = 100;
  1600.     playsound (self, CHAN_VOICE, "knight/ksight.wav", 1, ATTN_NORM);
  1601.  
  1602. }; 
  1603.  
  1604. void(float fl, float am) forge =
  1605. {
  1606.     if (fl == IT_SUPER_SHOTGUN)
  1607.     {
  1608.         if (self.armorvalue<20)
  1609.         {
  1610.             clientmsg(self, "Not enough armor to forge that.\n");
  1611.             return;
  1612.         }
  1613.         self.armorvalue = self.armorvalue - 20;
  1614.         self.ammo_shells = self.ammo_shells + 20;
  1615.         self.items = self.items | IT_SUPER_SHOTGUN;
  1616.         if (self.ammo_shells > 100) self.ammo_shells = 100;
  1617.         playsound (self, CHAN_VOICE, "knight/ksight.wav", 1, ATTN_NORM);
  1618.     }
  1619.     else if (fl == IT_NAILGUN)
  1620.     {
  1621.         if (self.armorvalue<20)
  1622.         {
  1623.             clientmsg(self, "Not enough armor to forge that.\n");
  1624.             return;
  1625.         }
  1626.         self.armorvalue = self.armorvalue - 20;
  1627.         self.ammo_nails = self.ammo_nails + 25;
  1628.         self.items = self.items | IT_NAILGUN;
  1629.         if (self.ammo_nails > 200) self.ammo_nails = 200;
  1630.         playsound (self, CHAN_VOICE, "knight/ksight.wav", 1, ATTN_NORM);
  1631.     }
  1632.     else if (fl == IT_SUPER_NAILGUN)
  1633.     {
  1634.         if (self.armorvalue < 30)
  1635.         {
  1636.             clientmsg(self, "Not enough armor to forge that.\n");
  1637.             return;
  1638.         }
  1639.         self.armorvalue = self.armorvalue - 30;
  1640.         self.ammo_nails = self.ammo_nails + 50;
  1641.         self.items = self.items | IT_SUPER_NAILGUN;
  1642.         if (self.ammo_nails > 200) self.ammo_nails = 200;
  1643.         playsound (self, CHAN_VOICE, "knight/ksight.wav", 1, ATTN_NORM);
  1644.     }
  1645.     else if (fl == IT_GRENADE_LAUNCHER)
  1646.     {
  1647.         if (self.armorvalue < 50)
  1648.         {
  1649.             clientmsg(self, "Not enough armor to forge that.\n");
  1650.             return;
  1651.         }
  1652.         self.armorvalue = self.armorvalue - 50;
  1653.         self.ammo_rockets = self.ammo_rockets + 5;
  1654.         self.items = self.items | IT_GRENADE_LAUNCHER;
  1655.         if (self.ammo_rockets > 100) self.ammo_rockets = 100;
  1656.         playsound (self, CHAN_VOICE, "knight/ksight.wav", 1, ATTN_NORM);
  1657.     }
  1658.     else if (fl == IT_ROCKET_LAUNCHER)
  1659.     {
  1660.         if (self.armorvalue < 75)
  1661.         {
  1662.             clientmsg(self, "Not enough armor to forge that.\n");
  1663.             return;
  1664.         }
  1665.         self.armorvalue = self.armorvalue - 75;
  1666.         self.ammo_rockets = self.ammo_rockets + 10;
  1667.         self.items = self.items | IT_ROCKET_LAUNCHER;
  1668.         if (self.ammo_rockets > 100) self.ammo_rockets = 100;
  1669.         playsound (self, CHAN_VOICE, "knight/ksight.wav", 1, ATTN_NORM);
  1670.     }
  1671.     else if (fl == IT_LIGHTNING)
  1672.     {
  1673.         if (self.armorvalue < 75)
  1674.         {
  1675.             clientmsg(self, "Not enough armor to forge that.\n");
  1676.             return;
  1677.         }
  1678.         self.armorvalue = self.armorvalue - 75;
  1679.         self.ammo_cells = self.ammo_cells + 30;
  1680.         self.items = self.items | IT_LIGHTNING;
  1681.         if (self.ammo_cells > 100) self.ammo_cells = 100;
  1682.         playsound (self, CHAN_VOICE, "knight/ksight.wav", 1, ATTN_NORM);
  1683.     }
  1684.     else return;
  1685. };
  1686.  
  1687. /*
  1688. ============
  1689. W_ChangeWeapon
  1690.  
  1691. ============
  1692. */
  1693. void() W_ChangeWeapon =
  1694. {
  1695.     local    float    it, am, fl, forged;
  1696.  
  1697.     forged=0;
  1698.     
  1699.     it = self.items;
  1700.     am = 0;
  1701.     if (self.impulse == 1) {
  1702.         if (self.weapon == IT_AXE)
  1703.             fl = IT_HOOK;
  1704.         else
  1705.             fl = IT_AXE;
  1706.     } else if (self.impulse == 31) {
  1707.         fl = IT_AXE;
  1708.     } else if (self.impulse == 2 || self.impulse == 32) {
  1709.         if ((self.weapon == IT_SHOTGUN) && (self.holy == 0))
  1710.             self.holy=1;
  1711.         else {
  1712.             self.holy=0;
  1713.             fl = IT_SHOTGUN;
  1714.             if (self.ammo_shells < 1)
  1715.                 am = 1;
  1716.         }
  1717.     } else if (self.impulse == 3 || self.impulse == 33) {
  1718.         fl = IT_SUPER_SHOTGUN;
  1719.         if (self.ammo_shells < 2)
  1720.             am = 1;
  1721.     } else if (self.impulse == 4 || self.impulse == 34) {
  1722.         fl = IT_NAILGUN;
  1723.         if (self.ammo_nails < 1)
  1724.             am = 1;
  1725.     } else if (self.impulse == 5) {
  1726.         fl = IT_SUPER_NAILGUN;
  1727.         if (self.ammo_nails < 2)
  1728.             am = 1;
  1729.     } else if (self.impulse == 35) {
  1730.         fl = IT_SUPER_NAILGUN;
  1731.         if (self.ammo_nails < 2)
  1732.             am = 1;
  1733.     } else if (self.impulse == 6 || self.impulse == 36) {
  1734.         if (self.weapon != IT_GRENADE_LAUNCHER)
  1735.             self.grenade_time=2.5;
  1736.         else
  1737.         {
  1738.             if (self.grenade_time == 2.5)
  1739.             {
  1740.                 sprint(self, "5 second one-shot grenade selected\n");
  1741.                 self.grenade_time=5;
  1742.             }
  1743.             else if (self.grenade_time == 5)
  1744.             {
  1745.                 sprint(self, "10 second one-shot grenade selected\n");
  1746.                 self.grenade_time=10;
  1747.             }
  1748.             else if (self.grenade_time == 10)
  1749.             {
  1750.                 sprint(self, "Normal (2.5 second) grenades selected\n");
  1751.                 self.grenade_time=2.5;
  1752.             }
  1753.         }
  1754.         fl = IT_GRENADE_LAUNCHER;
  1755.         if (self.ammo_rockets < 1)
  1756.             am = 1;
  1757.     } else if (self.impulse == 7 || self.impulse == 37) {
  1758.         fl = IT_ROCKET_LAUNCHER;
  1759.         if (self.ammo_rockets < 1)
  1760.             am = 1;
  1761.     } else if (self.impulse == 8 || self.impulse == 38) {
  1762.         fl = IT_LIGHTNING;
  1763.         if (self.ammo_cells < 1)
  1764.             am = 1;
  1765.     } else if (self.impulse == 22 || self.impulse == 39) {
  1766.         fl = IT_HOOK;
  1767.     }
  1768.  
  1769.     self.impulse = 0;
  1770.     
  1771.     if (!(self.items & fl))
  1772.     {
  1773.         // don't have the weapon or the ammo
  1774.         if (self.rune_num == ITEM_RUNE_VULCAN)
  1775.         {
  1776.             forge(fl, am);
  1777.             forged=1;
  1778.         }    
  1779.         else
  1780.         {
  1781.             sprint (self, "no weapon.\n");
  1782.             return;
  1783.         }
  1784.     }
  1785.     
  1786.     if (am && (forged != 1))
  1787.     {    // don't have the ammo
  1788.         if ((self.rune_num == ITEM_RUNE_VULCAN) && (forged != 1))
  1789.         {
  1790.             forged=1;
  1791.             forge_ammo(fl, am);
  1792.         }
  1793.         else
  1794.         {
  1795.             sprint (self, "not enough ammo.\n");
  1796.             return;
  1797.         }
  1798.     }
  1799.  
  1800.     if(!(self.items & fl))
  1801.         return;
  1802.  
  1803. //McBain: save current weapon
  1804. // For explicit weapon selection, allow previous weapon and new weapon to be
  1805. // same except for IT_HOOK.
  1806.     if (self.weapon != IT_HOOK || fl != IT_HOOK)
  1807.         self.previous_weapon = self.weapon;
  1808.  
  1809. //
  1810. // set weapon, set ammo
  1811. //
  1812.     self.weapon = fl;
  1813.  
  1814.     if ((self.weapon == self.previous_weapon) &&
  1815.     (self.rune_num == ITEM_RUNE_VULCAN) && (forged==0))
  1816.         forge_ammo(fl, am);
  1817.  
  1818.     NotifyWeapon();
  1819.     W_SetCurrentAmmo ();
  1820. };
  1821.  
  1822. /*
  1823. ============
  1824. CheatCommand
  1825. ============
  1826. */
  1827. void() CheatCommand =
  1828. {
  1829.     if (deathmatch || coop)
  1830.         return;
  1831.  
  1832.     self.ammo_rockets = 100;
  1833.     self.ammo_nails = 200;
  1834.     self.ammo_shells = 100;
  1835.     self.items = self.items | 
  1836.         IT_AXE |
  1837.         IT_HOOK |
  1838.         IT_SHOTGUN |
  1839.         IT_SUPER_SHOTGUN |
  1840.         IT_NAILGUN |
  1841.         IT_SUPER_NAILGUN |
  1842.         IT_GRENADE_LAUNCHER |
  1843.         IT_ROCKET_LAUNCHER |
  1844.         IT_KEY1 | IT_KEY2;
  1845.  
  1846.     self.ammo_cells = 200;
  1847.     self.items = self.items | IT_LIGHTNING;
  1848.  
  1849.     self.weapon = IT_ROCKET_LAUNCHER;
  1850.     self.impulse = 0;
  1851.     W_SetCurrentAmmo ();
  1852. };
  1853.  
  1854. /*
  1855. ============
  1856. CycleWeaponCommand
  1857.  
  1858. Go to the next weapon with ammo
  1859. ============
  1860. */
  1861. void() CycleWeaponCommand =
  1862. {
  1863.     local    float    it, am, loop_count;
  1864.  
  1865.     it = self.items;
  1866.     self.impulse = 0;
  1867.     
  1868. //McBain: save current weapon
  1869.     self.previous_weapon = self.weapon;
  1870.  
  1871.     loop_count = 0;
  1872.     while (1)
  1873.     {
  1874.         am = 0;
  1875.  
  1876.         if (self.weapon == IT_LIGHTNING) {
  1877.             self.weapon = IT_AXE;
  1878.         } else if (self.weapon == IT_AXE) {
  1879.             self.weapon = IT_HOOK;
  1880.         } else if (self.weapon == IT_HOOK) {
  1881.             self.weapon = IT_SHOTGUN;
  1882.             if (self.ammo_shells < 1)
  1883.                 am = 1;
  1884.         } else if (self.weapon == IT_SHOTGUN) {
  1885.             self.weapon = IT_SUPER_SHOTGUN;
  1886.             if (self.ammo_shells < 2)
  1887.                 am = 1;
  1888.         } else if (self.weapon == IT_SUPER_SHOTGUN) {
  1889.             self.weapon = IT_NAILGUN;
  1890.             if (self.ammo_nails < 1)
  1891.                 am = 1;
  1892.         } else if (self.weapon == IT_NAILGUN) {
  1893.             self.weapon = IT_SUPER_NAILGUN;
  1894.             if (self.ammo_nails < 2)
  1895.                 am = 1;
  1896.         } else if (self.weapon == IT_SUPER_NAILGUN) {
  1897.             self.weapon = IT_GRENADE_LAUNCHER;
  1898.             if (self.ammo_rockets < 1)
  1899.                 am = 1;
  1900.         } else if (self.weapon == IT_GRENADE_LAUNCHER) {
  1901.             self.weapon = IT_ROCKET_LAUNCHER;
  1902.             if (self.ammo_rockets < 1)
  1903.                 am = 1;
  1904.         } else if (self.weapon == IT_ROCKET_LAUNCHER) {
  1905.             self.weapon = IT_LIGHTNING;
  1906.             if (self.ammo_cells < 1)
  1907.                 am = 1;
  1908.         }
  1909.     
  1910.         if ( (it & self.weapon) && am == 0)
  1911.         {
  1912.             NotifyWeapon();
  1913.             W_SetCurrentAmmo ();
  1914.             return;
  1915.         }
  1916.         loop_count = loop_count + 1;
  1917.         if (loop_count > 8)
  1918.             return;
  1919.     }
  1920.  
  1921. };
  1922.  
  1923. /*
  1924. ============
  1925. CycleWeaponReverseCommand
  1926.  
  1927. Go to the prev weapon with ammo
  1928. ============
  1929. */
  1930. void() CycleWeaponReverseCommand =
  1931. {
  1932.     local    float    it, am;
  1933.     
  1934.     it = self.items;
  1935.     self.impulse = 0;
  1936.  
  1937. //McBain: save current weapon
  1938.     self.previous_weapon = self.weapon;
  1939.  
  1940.     while (1)
  1941.     {
  1942.         am = 0;
  1943.  
  1944.         if (self.weapon == IT_LIGHTNING)
  1945.         {
  1946.             self.weapon = IT_ROCKET_LAUNCHER;
  1947.             if (self.ammo_rockets < 1)
  1948.                 am = 1;
  1949.         }
  1950.         else if (self.weapon == IT_ROCKET_LAUNCHER)
  1951.         {
  1952.             self.weapon = IT_GRENADE_LAUNCHER;
  1953.             if (self.ammo_rockets < 1)
  1954.                 am = 1;
  1955.         }
  1956.         else if (self.weapon == IT_GRENADE_LAUNCHER)
  1957.         {
  1958.             self.weapon = IT_SUPER_NAILGUN;
  1959.             if (self.ammo_nails < 1)
  1960.                 am = 1;
  1961.         }
  1962.         else if (self.weapon == IT_SUPER_NAILGUN)
  1963.         {
  1964.             self.weapon = IT_NAILGUN;
  1965.             if (self.ammo_nails < 1)
  1966.                 am = 1;
  1967.         }
  1968.         else if (self.weapon == IT_NAILGUN)
  1969.         {
  1970.             self.weapon = IT_SUPER_SHOTGUN;
  1971.             if (self.ammo_shells < 2)
  1972.                 am = 1;
  1973.         }        
  1974.         else if (self.weapon == IT_SUPER_SHOTGUN)
  1975.         {
  1976.             self.weapon = IT_SHOTGUN;
  1977.             if (self.ammo_shells < 1)
  1978.                 am = 1;
  1979.         }
  1980.         else if (self.weapon == IT_SHOTGUN)
  1981.         {
  1982.             self.weapon = IT_HOOK;
  1983.         }
  1984.         else if (self.weapon == IT_HOOK)
  1985.         {
  1986.             self.weapon = IT_AXE;
  1987.         }
  1988.         else if (self.weapon == IT_AXE)
  1989.         {
  1990.             self.weapon = IT_LIGHTNING;
  1991.             if (self.ammo_cells < 1)
  1992.                 am = 1;
  1993.         }
  1994.     
  1995.         if ( (it & self.weapon) && am == 0)
  1996.         {
  1997.             NotifyWeapon();
  1998.             W_SetCurrentAmmo ();
  1999.             return;
  2000.         }
  2001.     }
  2002.  
  2003. };
  2004.  
  2005. //McBain: Here's the beef...
  2006. /*
  2007. ============
  2008. PreviousWeaponCommand
  2009. ============
  2010. */
  2011. void() PreviousWeaponCommand =
  2012. {
  2013.     local    float    fl, am;
  2014.     
  2015.     self.impulse = 0;
  2016.     am = 0;
  2017.  
  2018.     fl = self.weapon;
  2019.     self.weapon = self.previous_weapon;
  2020.     self.previous_weapon = fl;
  2021.  
  2022.     // this might not be the best method, but I'll be able to play sooner
  2023.     if (self.weapon == IT_SHOTGUN || self.weapon == IT_SUPER_SHOTGUN) {
  2024.         if (self.ammo_shells < 1)
  2025.             am = 1;
  2026.     }
  2027.     else if (self.weapon == IT_NAILGUN || self.weapon == IT_SUPER_NAILGUN) {
  2028.         if (self.ammo_nails < 1)
  2029.             am = 1;
  2030.     }
  2031.     else if (self.weapon == IT_GRENADE_LAUNCHER || self.weapon == IT_ROCKET_LAUNCHER) {
  2032.         if (self.ammo_rockets < 1)
  2033.             am = 1;
  2034.     }
  2035.     else if (self.weapon == IT_LIGHTNING) {
  2036.         if (self.ammo_cells < 1)
  2037.             am = 1;
  2038.     }
  2039.     // ignore AXE & HOOK -- no ammo needed
  2040.  
  2041.     if (am)
  2042.         self.weapon = W_BestWeapon ();
  2043.  
  2044.     W_SetCurrentAmmo ();
  2045. };
  2046.  
  2047. /*
  2048. ============
  2049. ServerflagsCommand
  2050.  
  2051. Just for development
  2052. ============
  2053. */
  2054. void() ServerflagsCommand =
  2055. {
  2056.     serverflags = serverflags * 2 + 1;
  2057. // ZOID:  Bug fix
  2058.     serverflags = (serverflags & 15);
  2059. };
  2060.  
  2061. //ZOID:  Uhm, where am I?
  2062. void() PrintLocation =
  2063. {
  2064.     local string p;
  2065.  
  2066.     p = vtos(self.origin);
  2067.  
  2068.     sprint(self, "You are at ");
  2069.     sprint(self, p);
  2070.     sprint(self, "\n");
  2071. };
  2072.  
  2073.  
  2074. /*
  2075. ============
  2076. ImpulseCommands
  2077.  
  2078. ============
  2079. */
  2080. //ZOID: Note, changed it all to an if/else construct.  No need to check
  2081. //remaining impulses if we have one already.  Much cleaner and a tad
  2082. //more efficient.  Using a non-existant impulse is still the worst case. :(
  2083. void() ImpulseCommands =
  2084. {
  2085.     local entity e;
  2086.  
  2087.     if ((self.needsreg == 2) && (self.impulse != 98))
  2088.         checkregimpulse();
  2089.     else if (self.accessparm) // admin functions
  2090.         CheckAdminCmd();
  2091.     else if ((self.impulse >= 1 && self.impulse <= 8) || self.impulse == 22 ||
  2092.         (self.impulse >= 31 && self.impulse <= 40))
  2093.         W_ChangeWeapon ();
  2094.  
  2095.     else if (self.impulse == 10)
  2096.         CycleWeaponCommand ();
  2097.  
  2098.     else if (self.impulse == 11)
  2099.         ServerflagsCommand ();
  2100.  
  2101.     else if (self.impulse == 12)
  2102.         CycleWeaponReverseCommand ();
  2103.  
  2104. //McBain: I picked 69 -- seems appropriate!  I hope 69 hasn't been used in
  2105. // other add-ons.  This is my first attempt at Quake C, and I hope I haven't
  2106. // violated any Quake C ettiquette.  :(
  2107.     else if (self.impulse == 69)
  2108.         PreviousWeaponCommand ();
  2109.  
  2110.     else if (self.impulse == 99)
  2111.         PrintLocation();
  2112.     else if (self.impulse == 98)
  2113.         regimpulse();
  2114.         
  2115. // *TEAMPLAY*
  2116. // If we're allowed to drop items, enable impulse 20 and 21
  2117.     else if ((teamplay & TEAM_DROP_ITEMS) && self.impulse == 20)
  2118.         TossBackpack ();
  2119.  
  2120.     else if ((teamplay & TEAM_DROP_ITEMS) && self.impulse == 21)
  2121.         TossWeapon ();
  2122.  
  2123. // *Capture The Flag - Status report by Wonko
  2124. // Impulse 23 prints the current status of your flag and the
  2125. // enemy flag (summarizes the endless messages)
  2126.     else if (self.impulse == 23)
  2127.         TeamFlagStatusReport();
  2128. // SUCK: Drop rune.
  2129.     else if (self.impulse == 24)
  2130.         TossRune();
  2131. // *TEAMPLAY*
  2132. // Impulse 25 prints info about the current teamplay settings.
  2133.     else if (self.impulse == 25)
  2134.         TeamPrintSettings ();
  2135. // SUCK: Help
  2136.     else if (self.impulse == 26)
  2137.         PrintHelp();
  2138. // SUCK: Rune info
  2139.     else if (self.impulse == 27)
  2140.         RuneInfo();
  2141.     else if (self.impulse == 28)
  2142.         GroupPowerInfo();
  2143. // SUCK: Status bar toggle.
  2144.     else if (self.impulse == 29)
  2145.     {
  2146.         if (self.status_time == -1)
  2147.             self.status_time = time;
  2148.         else
  2149.             self.status_time = -1;
  2150.     }
  2151.     else if (self.impulse >=71 && self.impulse <= 77)
  2152.     {
  2153.         // 71 - SOMETHINGx200
  2154.         // 72 - SOMETHINGx240
  2155.         // 73 - SOMETHINGx400
  2156.         // 74 - SOMETHINGx480
  2157.         // 75 - SOMETHINGx600
  2158.         // 76 - SOMETHINGx768
  2159.         // 77 - SOMETHINGx1024
  2160.         if (self.impulse == 71)
  2161.             self.bottom_line = 12;
  2162.         else if (self.impulse == 72)
  2163.             self.bottom_line = 17;
  2164.         else if (self.impulse == 73)
  2165.             self.bottom_line = 37;
  2166.         else if (self.impulse == 74)
  2167.             self.bottom_line = 47;
  2168.         else if (self.impulse == 75)
  2169.             self.bottom_line = 62;
  2170.         else if (self.impulse == 76)
  2171.             self.bottom_line = 83;
  2172.         else if (self.impulse == 77)
  2173.             self.bottom_line = 115; 
  2174.     }
  2175.     else if (self.impulse == 101)
  2176.         PrintStats();
  2177.     else if (self.impulse == 102)
  2178.         self.bottom_line = self.bottom_line + 1;
  2179.     else if (self.impulse == 103)
  2180.         self.bottom_line = self.bottom_line - 1;
  2181.     else if (self.impulse == 141)
  2182.         e=identify_player(1);
  2183.     else if (self.impulse == 111)
  2184.     {
  2185.             if (self.rune_num != ITEM_RUNE_LOKI)
  2186.                 return;
  2187.             msg_entity=self;
  2188.             if (self.loki_possessed)
  2189.             {
  2190.                 WriteByte(MSG_ONE, 5);
  2191.                 WriteEntity(MSG_ONE, self);
  2192.                 self.loki_possessed=0;
  2193.             }
  2194.             else
  2195.             {
  2196.                 e=identify_player(0);
  2197.                 if (e==world)
  2198.                 {
  2199.                     self.msg_center=1;
  2200.                     clientmsg(self, "No player to possess!\n");
  2201.                     return;
  2202.                 }
  2203.                 msg_entity=self;
  2204.                 WriteByte(MSG_ONE, 5);
  2205.                 WriteEntity(MSG_ONE, e);
  2206.                 self.loki_possessed=1;
  2207.                 self.loki_possession=e;
  2208.             }
  2209.     }
  2210.     else
  2211.         CheckAdminCmd();
  2212.         
  2213.     self.impulse = 0;
  2214. };
  2215.  
  2216. /*
  2217. ============
  2218. W_WeaponFrame
  2219.  
  2220. Called every frame so impulse events can be handled as well as possible
  2221. ============
  2222. */
  2223. void() W_WeaponFrame =
  2224. {
  2225.     if (time < self.attack_finished)
  2226.         return;
  2227.  
  2228. //ZOID: Only call ImpulseCommands() if needed!  This saves a good chunk
  2229. //of cpu.  'profile' in console listed ImpulseCommands() as #1 user of
  2230. //cpu (instructions), adding this one line caused it to not even be in
  2231. //the top ten.
  2232.     if (self.impulse)
  2233.         ImpulseCommands ();
  2234.     
  2235. // check for attack
  2236.     if (self.button0)
  2237.     {
  2238.         SuperDamageSound ();
  2239.         W_Attack ();
  2240.     }
  2241. };
  2242.  
  2243. /*
  2244. ========
  2245. SuperDamageSound
  2246.  
  2247. Plays sound if needed
  2248. ========
  2249. */
  2250. void() SuperDamageSound =
  2251. {
  2252. // RUNE play super damage sound if player has Black Magic, too
  2253.     if (self.super_damage_finished > time ||
  2254.         (self.rune_num == ITEM_RUNE_DBLDMG) ||
  2255.         (self.rune_num == ITEM_RUNE_MARS) &&
  2256.         (self.weapon != IT_HOOK)) {
  2257.         if (self.super_sound < time) {
  2258.             self.super_sound = time + 1;
  2259.             playsound (self, CHAN_BODY, "items/damage3.wav", 1, ATTN_NORM);
  2260.         }
  2261.     }
  2262.     if ((self.rune_num == ITEM_RUNE_WEREWOLF) && (self.rune_sound_start < time) && (self.weapon != IT_HOOK))
  2263.     {
  2264.         sound(self, CHAN_VOICE, "shambler/sidle.wav", 1, ATTN_NORM);
  2265.         self.rune_sound_start = time + 0.8;
  2266.     }
  2267.     else
  2268.     if ((self.rune_num == ITEM_RUNE_VAMPIRE) && (self.rune_sound_start < time) && (self.weapon != IT_HOOK))
  2269.     {
  2270.         sound(self, CHAN_VOICE, "wizard/widle2.wav", 1, ATTN_NORM);
  2271.         self.rune_sound_start = time + 2.5;
  2272.     }
  2273.     return;
  2274. };
  2275.  
  2276. /*
  2277. ========
  2278. RegenerationSound
  2279.  
  2280. Plays sound if needed
  2281. ========
  2282. */
  2283. void() RegenerationSound =
  2284. {
  2285. // RUNE play healing sound if player has Elder Magic
  2286.     if (self.rune_num == ITEM_RUNE_REGEN) {
  2287.         if (self.regeneration_sound < time) {
  2288.             self.regeneration_sound = time + 1;
  2289.             sound(self, CHAN_BODY, "items/r_item1.wav", 1, ATTN_NORM);
  2290.         }
  2291.     }
  2292.     return;
  2293. };
  2294.  
  2295. /*
  2296. ========
  2297. HasteSound
  2298.  
  2299. Plays sound if needed
  2300. ========
  2301. */
  2302. void() HasteSound =
  2303. {
  2304. // RUNE play haste (Chthon's roar) sound if player has Hell Magic
  2305.     if (self.rune_num == ITEM_RUNE_HASTE) {
  2306.         if (self.haste_sound < time) {
  2307.             self.haste_sound = time + 2;
  2308.             sound(self, CHAN_BODY, "boss1/sight1.wav", 1, ATTN_NORM);
  2309.         }
  2310.     }
  2311.     return;
  2312. };
  2313.  
  2314.